﻿using FreeSql;
using FreeSql;
using FreeSql.DataAnnotations;
using KrasDD.Models;
using Microsoft.Data.SqlClient;
using System.Data;
using System.IO;
using System.Reflection;
using System.Security.Principal;

namespace KrasDD.Extensions;

public static class FreeSqlExtension
{
    private static string GetConnectionString(this FreeSqlBuilder @this)
    {
        Type type = @this.GetType();
        FieldInfo fieldInfo = type.GetField(
            "_masterConnectionString",
            BindingFlags.NonPublic | BindingFlags.Instance
        );
        if (fieldInfo is null)
        {
            throw new ArgumentException("_masterConnectionString is null");
        }
        return fieldInfo.GetValue(@this).ToString();
    }

    /// <summary>
    /// 请在UseConnectionString配置后调用此方法
    /// </summary>
    /// <param name="this"></param>
    /// <returns></returns>
    public static FreeSqlBuilder CreateDatabaseIfNotExists(this FreeSqlBuilder @this)
    {
        FieldInfo dataTypeFieldInfo = @this
            .GetType()
            .GetField("_dataType", BindingFlags.NonPublic | BindingFlags.Instance);

        if (dataTypeFieldInfo is null)
        {
            throw new ArgumentException("_dataType is null");
        }

        string connectionString = GetConnectionString(@this);
        DataType dbType = (DataType)dataTypeFieldInfo.GetValue(@this);

        switch (dbType)
        {
            case DataType.SqlServer:
                return @this.CreateDatabaseIfNotExistsSqlServer(connectionString);
            case DataType.Sqlite:
                return @this;
            default:
                throw new NotSupportedException($"不支持创建数据库类型: {dbType}");
        }
    }

    /// <summary>
    /// 创建SQL Server数据库（如果不存在）
    /// </summary>
    /// <param name="this"></param>
    /// <param name="connectionString"></param>
    /// <returns></returns>
    public static FreeSqlBuilder CreateDatabaseIfNotExistsSqlServer(
        this FreeSqlBuilder @this,
        string connectionString = ""
    )
    {
        if (connectionString == "")
        {
            connectionString = GetConnectionString(@this);
        }

        SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(connectionString);
        string createDatabaseSql;

        if (!string.IsNullOrEmpty(builder.AttachDBFilename))
        {
            string fileName = ExpandFileName(builder.AttachDBFilename);
            string name = Path.GetFileNameWithoutExtension(fileName);
            string logFileName = Path.ChangeExtension(fileName, ".ldf");
            createDatabaseSql =
                @$"CREATE DATABASE {builder.InitialCatalog}   on  primary   
                (
                    name = '{name}',
                    filename = '{fileName}'
                )
                log on
                (
                    name= '{name}_log',
                    filename = '{logFileName}'
                )";
        }
        else
        {
            createDatabaseSql = @$"CREATE DATABASE {builder.InitialCatalog}";
        }

        // 构建master数据库连接字符串
        string masterConnectionString =
            $"Data Source={builder.DataSource};Integrated Security={builder.IntegratedSecurity};";
        if (!builder.IntegratedSecurity)
        {
            masterConnectionString += $"User ID={builder.UserID};Password={builder.Password};";
        }
        masterConnectionString +=
            "Initial Catalog=master;Min pool size=1;TrustServerCertificate=True;";

        using SqlConnection cnn = new SqlConnection(masterConnectionString);
        cnn.Open();

        using SqlCommand cmd = cnn.CreateCommand();
        cmd.CommandText = $"select * from sysdatabases where name = '{builder.InitialCatalog}'";

        SqlDataAdapter apter = new SqlDataAdapter(cmd);
        DataSet ds = new DataSet();
        apter.Fill(ds);

        if (ds.Tables[0].Rows.Count == 0)
        {
            cmd.CommandText = createDatabaseSql;
            cmd.ExecuteNonQuery();
        }

        return @this;
    }

    /// <summary>
    /// 创建SQL Server架构（如果不存在）
    /// </summary>
    /// <param name="this"></param>
    /// <param name="schemaName">架构名称</param>
    /// <returns></returns>
    public static FreeSqlBuilder CreateSchemaIfNotExistsSqlServer(
        this FreeSqlBuilder @this,
        string schemaName
    )
    {
        string connectionString = GetConnectionString(@this);
        SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(connectionString);
        // 构建master数据库连接字符串
        string masterConnectionString =
            $"Data Source={builder.DataSource};Integrated Security={builder.IntegratedSecurity};";
        if (!builder.IntegratedSecurity)
        {
            masterConnectionString += $"User ID={builder.UserID};Password={builder.Password};";
        }
        masterConnectionString +=
            "Initial Catalog=master;Min pool size=1;TrustServerCertificate=True;";

        using SqlConnection cnn = new SqlConnection(masterConnectionString);
        cnn.Open();

        using SqlCommand cmd = cnn.CreateCommand();
        cmd.CommandText = $"SELECT COUNT(*) FROM sys.schemas WHERE name = '{schemaName}'";

        var result = cmd.ExecuteScalar();
        int schemaCount = result != null ? Convert.ToInt32(result) : 0;

        if (schemaCount == 0)
        {
            cmd.CommandText = $"CREATE SCHEMA [{schemaName}]";
            cmd.ExecuteNonQuery();
        }

        return @this;
    }

    /// <summary>
    /// 展开文件名，处理 |DataDirectory| 标记
    /// </summary>
    /// <param name="fileName"></param>
    /// <returns></returns>
    private static string ExpandFileName(string fileName)
    {
        if (fileName.StartsWith("|DataDirectory|", StringComparison.OrdinalIgnoreCase))
        {
            var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory") as string;
            if (string.IsNullOrEmpty(dataDirectory))
            {
                dataDirectory = AppDomain.CurrentDomain.BaseDirectory;
            }
            string name = fileName
                .Replace("\\", "")
                .Replace("/", "")
                .Substring("|DataDirectory|".Length);
            fileName = Path.Combine(dataDirectory, name);
        }
        if (!Directory.Exists(Path.GetDirectoryName(fileName)))
        {
            Directory.CreateDirectory(Path.GetDirectoryName(fileName));
        }
        return Path.GetFullPath(fileName);
    }


  
}
